"""
Connection Monitor Service
Monitors WebSocket connections and performs periodic health checks.
"""

import asyncio
import logging
from datetime import datetime, timedelta
from typing import Optional

from .websocket_manager import connection_manager

logger = logging.getLogger(__name__)


class ConnectionMonitor:
    """
    Monitors WebSocket connections for health and performs cleanup
    """
    
    def __init__(self, ping_interval: int = 30, cleanup_interval: int = 60):
        """
        Initialize connection monitor
        
        Args:
            ping_interval: Seconds between ping checks
            cleanup_interval: Seconds between cleanup operations
        """
        self.ping_interval = ping_interval
        self.cleanup_interval = cleanup_interval
        self.is_running = False
        self._monitor_task: Optional[asyncio.Task] = None
        self._cleanup_task: Optional[asyncio.Task] = None
    
    async def start_monitoring(self):
        """Start the connection monitoring tasks"""
        if self.is_running:
            logger.warning("Connection monitor is already running")
            return
        
        self.is_running = True
        logger.info("Starting connection monitor")
        
        # Start monitoring tasks
        self._monitor_task = asyncio.create_task(self._ping_loop())
        self._cleanup_task = asyncio.create_task(self._cleanup_loop())
    
    async def stop_monitoring(self):
        """Stop the connection monitoring tasks"""
        if not self.is_running:
            return
        
        self.is_running = False
        logger.info("Stopping connection monitor")
        
        # Cancel monitoring tasks
        if self._monitor_task:
            self._monitor_task.cancel()
            try:
                await self._monitor_task
            except asyncio.CancelledError:
                pass
        
        if self._cleanup_task:
            self._cleanup_task.cancel()
            try:
                await self._cleanup_task
            except asyncio.CancelledError:
                pass
    
    async def _ping_loop(self):
        """Periodically ping all connections to check health"""
        while self.is_running:
            try:
                await asyncio.sleep(self.ping_interval)
                
                if connection_manager.get_connection_count() > 0:
                    logger.debug(f"Pinging {connection_manager.get_connection_count()} connections")
                    await connection_manager.ping_all_connections()
                
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Error in ping loop: {e}")
    
    async def _cleanup_loop(self):
        """Periodically cleanup stale connections and perform maintenance"""
        while self.is_running:
            try:
                await asyncio.sleep(self.cleanup_interval)
                await self._perform_cleanup()
                
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Error in cleanup loop: {e}")
    
    async def _perform_cleanup(self):
        """Perform connection cleanup and maintenance"""
        current_time = datetime.now()
        stale_threshold = timedelta(minutes=10)  # Consider connections stale after 10 minutes of inactivity
        
        stale_sessions = []
        
        # Check for stale connections
        for session_id in list(connection_manager.active_connections.keys()):
            connection_info = connection_manager.get_connection_info(session_id)
            
            if connection_info:
                last_ping = connection_info.get("last_ping")
                if last_ping and (current_time - last_ping) > stale_threshold:
                    stale_sessions.append(session_id)
        
        # Clean up stale connections
        for session_id in stale_sessions:
            logger.info(f"Cleaning up stale connection for session: {session_id}")
            await connection_manager.disconnect(session_id)
        
        if stale_sessions:
            logger.info(f"Cleaned up {len(stale_sessions)} stale connections")
        
        # Log connection statistics
        active_count = connection_manager.get_connection_count()
        if active_count > 0:
            logger.debug(f"Active connections: {active_count}")


# Global connection monitor instance
connection_monitor = ConnectionMonitor()